﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compiler
{
    /// <summary>
    /// 词法分析
    /// </summary>
    public static class LexicalAnalysis
    {
        /// <summary>
        /// 分析字符串
        /// </summary>
        public static string SourceCode { get; set; }
        /// <summary>
        /// 分析
        /// </summary>
        public static void Analyse()
        {
            if (Lexer.Tokenize())
            {
                Compiler.WriteLine("-词法分析完成");
            }
            else
            {
                Compiler.WriteLine("-词法分析失败");
            }

            Compiler.WriteLine($" Value\tLexeme\tType\t\t");
            foreach (Token token in Token.Tokens)
            {
                Compiler.WriteLine($" {token.Value}\t{token.Lexeme}\t{token.Type}\t");
                Token.Queue.Enqueue(token);
            }
            Token.Queue.Enqueue(new Token("#", "Boundary", "#"));
        }
        /// <summary>
        /// 初始化
        /// </summary>
        public static void Init()
        {
            SourceCode = "";
            Lexer.tokens = Token.Tokens;
            Lexer.readPointer = 0;
        }

        /// <summary>
        /// 词法分析器
        /// </summary>
        private static class Lexer
        {
            /// <summary>
            /// 分析出的记号
            /// </summary>
            public static List<Token> tokens;
            /// <summary>
            /// 分析器指针当前位置
            /// </summary>
            public static int readPointer;
            /// <summary>
            /// 分析出Token
            /// </summary>
            public static bool Tokenize()
            {
                while (readPointer < SourceCode.Length)
                {
                    char currentChar = SourceCode[readPointer];

                    //跳过空格
                    if (char.IsWhiteSpace(currentChar))
                    {
                        readPointer++;
                    }
                    //字母
                    else if (char.IsLetter(currentChar))
                    {
                        //先读取出一个完整的标识名
                        string identifier = ReadIdentifier();
                        //判断是关键字还是标识符
                        if (SymbolTable.IsKeyword(identifier))
                        {
                            tokens.Add(new Token(identifier, "Keyword", identifier));
                        }
                        else
                        {
                            //将标识符记录到符号表中
                            SymbolTable.RecordIdentifier(identifier);
                            tokens.Add(new Token("ID", "Identifier", identifier));
                        }
                        continue;
                    }
                    //常数
                    else if (char.IsDigit(currentChar))
                    {
                        string number = ReadNumber();
                        tokens.Add(new Token("NUM", "Number", number));
                        continue;
                    }
                    //操作符
                    else if (SymbolTable.IsOperator(currentChar.ToString()))
                    {
                        string op = ReadOperator();
                        tokens.Add(new Token(op, "Operator", op));
                        continue;
                    }
                    //边界符
                    else if (SymbolTable.IsBoundary(currentChar.ToString()))
                    {
                        string op = ReadOperator();
                        tokens.Add(new Token(op, "Boundary", op));
                        continue;
                    }
                    //非法字符
                    else
                    {
                        Compiler.Log(new Exception($"非法字符 {currentChar}"));
                        return false;
                    }
                }
                return true;
            }
            /// <summary>
            /// 读取一个标识符
            /// </summary>
            private static string ReadIdentifier()
            {
                string identifier = SourceCode[readPointer].ToString();
                readPointer++;

                while (readPointer < SourceCode.Length && (char.IsLetterOrDigit(SourceCode[readPointer]) || SourceCode[readPointer] == '_'))
                {
                    identifier += SourceCode[readPointer];
                    readPointer++;
                }
                return identifier;
            }
            /// <summary>
            /// 读取一个常数
            /// </summary>
            private static string ReadNumber()
            {
                string number = SourceCode[readPointer].ToString();
                readPointer++;

                while (readPointer < SourceCode.Length && char.IsDigit(SourceCode[readPointer]))
                {
                    number += SourceCode[readPointer];
                    readPointer++;
                }
                return number;
            }
            /// <summary>
            /// 读取一个操作符
            /// </summary>
            private static string ReadOperator()
            {
                string op = SourceCode[readPointer].ToString();
                readPointer++;

                if (readPointer < SourceCode.Length && SymbolTable.IsOperator(op + SourceCode[readPointer]))
                {
                    op += SourceCode[readPointer];
                    readPointer++;
                }
                return op;
            }
        }
    }
}
